/*
 * Middleware
 * Copyright (C) 2010/11
 * Riccardo Pulvirenti, Giuseppe Ravidà, Andrea Tino
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANDABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses
 */

/*!
 * File: address.hpp
 */

#ifndef _ADDRESS_HPP_
#define _ADDRESS_HPP_

#include <iostream>
#include <string>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

//-----------------------------------------------------------------------------
// Enum, struct, aliases
namespace middleware {
/*! InetIpAddr
 * \brief Internet Ip v4 address.
 *
 * Internet Ip v4 address that locates the peer in the network.
 */
typedef std::string InetIpAddr;
/*! InetPort
 * \brief Represents an Internet TCP Port number ranging from 0 to 2^16.
 *
 * Number representing the port where one of the peer's components will bind
 * in order to listen for incoming information from the network.
 */
typedef unsigned int InetPort;
}
//-----------------------------------------------------------------------------
// Class definitions
namespace middleware {
/*! \class Address
 * \brief Represents a complete address for a peer.
 *
 * Address embodies four important information of the peer regarding its
 * location in the network: its Ip v4 address and its ports. A peer binds
 * always to three ports: one for Manager, one for WorkerDiscovery and another
 * one for Worker.
 */
class Address {
public:
	/*!
	 * Constructs a private loopback address setting invalid ports (0).
	 */
	Address() {
		this->_ip = "127.0.0.1";
		this->_port = 0;
		this->_port_disc = 0;
		this->_port_w = 0;
	}
	/*!
	 * Constructs an address basing on provided IP and ports.
	 * \param ip An IP v4 address.
	 * \param port Port where Manager listens to incoming TaskDescriptor.
	 * \param port_disc Port where WorkerDiscovery listens to incoming WorkerDescriptor.
	 * \param port_w Port where Worker listens to incoming executable tasks' Data.
	 */
	Address(InetIpAddr ip, InetPort port, InetPort port_disc, InetPort port_w) {
		this->_ip = ip;
		this->_port = port;
		this->_port_disc = port_disc;
		this->_port_w = port_w;
	}
	/*!
	 * Copy constructor.
	 */
	Address(const Address& addr) {
		this->_ip = addr._ip;
		this->_port = addr._port;
		this->_port_disc = addr._port_disc;
		this->_port_w = addr._port_w;
	}
	/*!
	 * Destructor
	 */
	~Address() {

	}
	/*!
	 * Gets the IP v4 address where the peer is located.
	 * \return Returns the InetIpAddr of the peer.
	 */
	InetIpAddr get_ip() const {
		return this->_ip;
	}
	/*!
	 * Sets the IP v4 address where the peer is located.
	 * \param ip InetIpAddr to set.
	 */
	void set_ip(InetIpAddr ip) {
		this->_ip = ip;
	}
	/*!
	 * Gets the port where the Manager listens to incoming TaskDescriptor.
	 * \return Returns the InetPort of where the Manager is listening.
	 */
	InetPort get_port() const {
		return this->_port;
	}
	/*!
	 * Gets the port where the WorkerDiscovery listens to incoming WorkerDescriptor.
	 * \return Returns the InetPort of where the WorkerDiscovery is listening.
	 */
	InetPort get_port_disc() const {
		return this->_port_disc;
	}
	/*!
	 * Gets the port where the Worker listens to incoming Data.
	 * \return Returns the InetPort of where the Worker is listening.
	 */
	InetPort get_port_w() const {
		return this->_port_w;
	}
	/*!
	 * Sets the port where the Manager listens to incoming TaskDescriptor.
	 * \param port The InetPort where the Manager will have to listen.
	 */
	void set_port(InetPort port) {
		this->_port = port;
	}
	/*!
	 * Sets the port where the WorkerDiscovery listens to incoming WorkerDescriptor.
	 * \param port The InetPort where the WorkerDiscovery will have to listen.
	 */
	void set_port_disc(InetPort port) {
		this->_port_disc = port;
	}
	/*!
	 * Sets the port where the Worker listens to incoming Data.
	 * \param port The InetPort where the Worker will have to listen.
	 */
	void set_port_w(InetPort port) {
		this->_port_w = port;
	}
	/*!
	 * \brief Comparison between two Address.
	 *
	 * Two Address are equal when they have the same Ip and Ports.
	 */
	bool operator==(const Address& addr) const {
		bool res = (this->_ip) == (addr._ip);
		res = res && (this->_port == addr._port);
		res = res && (this->_port_disc == addr._port_disc);
		res = res && (this->_port_w == addr._port_w);
		return res;
	}
	/*!
	 * \brief Negative comparison between two Address.
	 *
	 * Two Address are not equal when they have at least Ip or one port unequal.
	 */
	bool operator!=(const Address& addr) const {
		return (*this == addr);
	}
private:
	friend class boost::serialization::access;
	/*!
	 * BOOST serialization function.
	 */
	template<class Archive>
	void serialize(Archive & ar, const unsigned int version) {
		ar & _ip;
		ar & _port;
		ar & _port_disc;
		ar & _port_w;
	}
	/*!
	 * Holds ip address in the form x1x2x3.y1y2y3.z1z2z3.k1k2k3
	 */
	InetIpAddr _ip;
	/*!
	 * Holds port to manager.
	 */
	InetPort _port;
	/*!
	 * Holds port to discovery.
	 */
	InetPort _port_disc;
	/*!
	 * Holds port to worker.
	 */
	InetPort _port_w;
}; /* Address */
} /* middleware */

#endif
